﻿using System;
using System.Linq;
using Yamfinder.Data;

namespace Yamfinder.Service
{
    public class UserService : IUserService
    {
        private readonly IUserRepository _userRepository;
        private readonly ICryptoService _cryptoService;

        public UserService(IUserRepository userRepository, ICryptoService cryptoService)
        {
            _userRepository = userRepository;
            _cryptoService = cryptoService;
        }

        public bool ValidateUser(string username, string password)
        {
            if (string.IsNullOrEmpty(username)) throw new ArgumentException("Username cannot be null or empty.", "username");

            var user = _userRepository.Get(username);

            if (user == null)
            {
                return false; //No idea who this user is
            }

            return _cryptoService.Match(password, user.Password);
        }

        public bool IsUserAdmin(string username)
        {
            if (string.IsNullOrEmpty(username)) throw new ArgumentException("Username cannot be null or empty.", "username");

            var user = _userRepository.Get(username);
            return user.IsAdmin;
        }

        public void CreateUser(string username, string password, string firstname, string lastname)
        {
            if (string.IsNullOrEmpty(username)) throw new ArgumentException("Username cannot be null or empty.", "username");
            if (string.IsNullOrEmpty(password)) throw new ArgumentException("Password cannot be null or empty.", "password");
            if (string.IsNullOrEmpty(firstname)) throw new ArgumentException("First name cannot be null or empty.", "firstname");
            if (string.IsNullOrEmpty(lastname)) throw new ArgumentException("Last name cannot be null or empty", "lastname");

            var user = new Data.User
                            {
                                Firstname = firstname,
                                IsAdmin = false,
                                Lastname = lastname,
                                Username = username,
                                Password = _cryptoService.GetHash(password)
                            };
            _userRepository.Insert(user);
        }

        public void RemoveUser(string username)
        {
            if (string.IsNullOrEmpty(username)) throw new ArgumentException("Username cannot be null or empty.", "username");

            _userRepository.Remove(username);
        }

        public void CreateAdmin(string username)
        {
            if (string.IsNullOrEmpty(username)) throw new ArgumentException("Username cannot be null or empty.", "username");

            var user = _userRepository.Get(username);
            user.IsAdmin = true;

            _userRepository.Save(user);
        }

        public void RemoveAdmin(string username)
        {
            if (string.IsNullOrEmpty(username)) throw new ArgumentException("Username cannot be null or empty.", "username");

            var user = _userRepository.Get(username);
            user.IsAdmin = false;

            _userRepository.Save(user);
        }

        public void SetPassword(string username, string password)
        {
            if (string.IsNullOrEmpty(username)) throw new ArgumentException("Username cannot be null or empty.", "username");
            if (string.IsNullOrEmpty(password)) throw new ArgumentException("Password cannot be null or empty.","password");

            var user = _userRepository.Get(username);
            user.Password = _cryptoService.GetHash(password);

            _userRepository.Save(user);
        }

        public User GetUser(string username)
        {
            return new User(_userRepository.Get(username));
        }

        public IQueryable<User> GetUsers()
        {
            var rawUsers = _userRepository.Query();
            return rawUsers.Select(x => new User(x));
        }

        public PaginatedList<User> GetUsers(int pageIndex, int pageSize)
        {
            var rawUsers = _userRepository.Query();
            
            var totalCount = rawUsers.Count();
            var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);

            rawUsers = rawUsers.Skip(pageIndex * pageSize).Take(pageSize);

            return new PaginatedList<User>(rawUsers.Select(x => new User(x)), pageIndex, pageSize, totalCount, totalPages);
        }

        public bool IsFirstRun()
        {
            //This is a check to make sure there is always an admin
            return _userRepository.Query().Where(x => x.IsAdmin).Count() <= 0;
        }
    }
}
